package countor;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * =================题目	=====================<br>
 * =依次打印最近10天登陆最频繁的10人的登陆次数 =<br>
 * ==========================================<br><br>
 * 
 * 最普通的阻塞计数,最大计数Long.MAX_VALUE<br>
 * 定制阻塞计数器计数,最大计数Long.MAX_VALUE<br>
 * 通用阻塞计数器计数,最大计数Long.MAX_VALUE<br>
 * 并发计数，使用Java8Steam，最大计数Integer.MAX_VALUE<br>
 * 并发计数器计数,最大计数Long.MAX_VALUE<br>
 * 并发索引计数器计数，最大计数Long.MAX_VALUE*(Long.MAX_VALUE+1)<br>
 * 并发大数计数器计数，宇宙计数器，最大计数：一切都安静了，数值已没有意义，看你有多少资源<br>
 * @author dingnate
 *
 */
public class Main {

	public static void main(String[] args) {
		System.out.println("===================最普通的阻塞计数,最大计数Long.MAX_VALUE========================");
		userLoginCountSortUseTwoMap();
		System.out.println("===================定制阻塞计数器计数,最大计数Long.MAX_VALUE========================");
		userLoginCountSortUseUserLoginCountor();
		System.out.println("===================通用阻塞计数器计数,最大计数Long.MAX_VALUE=======================");
		userLoginCountSortUseNormalCountor();
		System.out.println("===================并发计数，使用Java8Steam，最大计数Integer.MAX_VALUE========================");
		userLoginCountSortUseJava8Steam();
		System.out.println("===================并发计数器计数,最大计数Long.MAX_VALUE========================");
		userLoginCountSortUseAtomCountor();
		System.out
				.println("===================并发索引计数器计数，最大计数Long.MAX_VALUE*(Long.MAX_VALUE+1)========================");
		userLoginCountSortUseAtomIndexCountor();
		System.out.println("===================并发大数计数器计数，宇宙计数器，最大计数：一切都安静了，数值已没有意义，看你有多少资源========================");
		userLoginCountSortUseAtomBigIntegerCountor();
	}

	private static void userLoginCountSortUseAtomBigIntegerCountor() {
		//filter
		//count
		ConcurrentHashMap<Long, AtomBigIntegerCountor<User>> id2Countors = new ConcurrentHashMap<Long, AtomBigIntegerCountor<User>>();
		long loginTimeBorder = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10);
		UserLoginData.getUsers().parallelStream().filter(u -> (u.getLoginTime() >= loginTimeBorder))
				.forEach(new Consumer<User>() {
					@Override
					public void accept(User t) {
						AtomBigIntegerCountor<User> atomCountor = id2Countors.get(t.getUserId());
						if (atomCountor != null) {
							atomCountor.incr();
							return;
						}
						atomCountor = new AtomBigIntegerCountor<User>(t);
						AtomBigIntegerCountor<User> preCountor = id2Countors.putIfAbsent(t.getUserId(), atomCountor);
						if (preCountor != null)
							atomCountor = preCountor;
						atomCountor.incr();
					}
				});
		//sort
		//print
		id2Countors.values().stream().sorted((c1, c2) -> c2.getCount().subtract(c1.getCount()).signum()).limit(10)
				.forEach(c -> System.out.println(c));
	}

	/**
	 * 并发索引计数器计数，最大计数Long.MAX_VALUE*(Long.MAX_VALUE+1)
	 */
	private static void userLoginCountSortUseAtomIndexCountor() {
		//filter
		//count
		ConcurrentHashMap<Long, AtomIndexCountor<User>> id2Countors = new ConcurrentHashMap<Long, AtomIndexCountor<User>>();
		long loginTimeBorder = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10);
		UserLoginData.getUsers().parallelStream().filter(u -> (u.getLoginTime() >= loginTimeBorder))
				.forEach(new Consumer<User>() {
					@Override
					public void accept(User t) {
						AtomIndexCountor<User> atomCountor = id2Countors.get(t.getUserId());
						if (atomCountor != null) {
							atomCountor.incr();
							return;
						}
						atomCountor = new AtomIndexCountor<User>(t);
						AtomIndexCountor<User> preCountor = id2Countors.putIfAbsent(t.getUserId(), atomCountor);
						if (preCountor != null)
							atomCountor = preCountor;
						atomCountor.incr();
					}
				});
		//sort
		//print
		id2Countors.values().stream().sorted((c1, c2) -> c2.getCount().subtract(c1.getCount()).signum()).limit(10)
				.forEach(c -> System.out.println(c));
	}

	/**
	 * 并发计数器计数,最大计数Long.MAX_VALUE
	 */
	private static void userLoginCountSortUseAtomCountor() {
		//filter
		//count
		ConcurrentHashMap<Long, AtomCountor<User>> id2Countors = new ConcurrentHashMap<Long, AtomCountor<User>>();
		long loginTimeBorder = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10);
		UserLoginData.getUsers().parallelStream().filter(u -> (u.getLoginTime() >= loginTimeBorder))
				.forEach(new Consumer<User>() {
					@Override
					public void accept(User t) {
						AtomCountor<User> atomCountor = id2Countors.get(t.getUserId());
						if (atomCountor != null) {
							atomCountor.incr();
							return;
						}
						atomCountor = new AtomCountor<User>(t);
						AtomCountor<User> preCountor = id2Countors.putIfAbsent(t.getUserId(), atomCountor);
						if (preCountor != null)
							atomCountor = preCountor;
						atomCountor.incr();
					}
				});
		//sort
		//print
		id2Countors.values().stream().sorted((c1, c2) -> BigInteger.valueOf(c2.getCount() - c1.getCount()).signum())
				.limit(10).forEach(c -> System.out.println(c));
	}

	/**
	 * 并发计数，使用Java8Steam，最大计数Integer.MAX_VALUE
	 */
	private static void userLoginCountSortUseJava8Steam() {
		long loginTimeBorder = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10);
		UserLoginData.getUsers().parallelStream().filter(u -> (u.getLoginTime() >= loginTimeBorder))
				.collect(Collectors.groupingBy(User::getUserId)).values().stream()
				.sorted((l1, l2) -> l2.size() - l1.size()).limit(10)
				.forEach(l -> System.out.println("count=" + l.size() + ", User=" + l.get(0)));
	}

	/**
	 * 普通计数器阻塞计数,最大计数Long.MAX_VALUE
	 */
	private static void userLoginCountSortUseNormalCountor() {
		List<User> users = UserLoginData.getUsers();
		//filter
		//count
		long loginTimeBorder = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10);
		HashMap<Long, NormalCountor<User>> id2Countors = new HashMap<Long, NormalCountor<User>>();
		for (User user : users) {
			if (user.getLoginTime() < loginTimeBorder)
				continue;
			NormalCountor<User> countor = id2Countors.get(user.getUserId());
			if (countor == null) {
				countor = new NormalCountor<User>(user);
				id2Countors.put(user.getUserId(), countor);
			}
			countor.incr();
		}
		//sort
		//print
		@SuppressWarnings("unchecked")
		NormalCountor<User>[] countors = id2Countors.values().toArray(new NormalCountor[0]);
		int scope = Math.min(10, countors.length);
		for (int i = 0; i < scope; i++) {
			for (int j = i + 1; j < countors.length; j++) {
				if (countors[j].getCount() > countors[i].getCount()) {
					NormalCountor<User> temp = countors[j];
					countors[j] = countors[i];
					countors[i] = temp;
				}
			}
			System.out.println(countors[i]);
		}
	}

	/**
	 * 定制计数器阻塞计数,最大计数Long.MAX_VALUE
	 */
	private static void userLoginCountSortUseUserLoginCountor() {
		List<User> users = UserLoginData.getUsers();
		//filter
		//count
		long loginTimeBorder = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10);
		HashMap<Long, UserLoginCountor> map = new HashMap<Long, UserLoginCountor>();
		for (User user : users) {
			if (user.getLoginTime() < loginTimeBorder)
				continue;
			UserLoginCountor countor = map.get(user.getUserId());
			if (countor == null) {
				countor = new UserLoginCountor(user);
				map.put(user.getUserId(), countor);
			}
			countor.incr();
		}
		//sort
		//print
		UserLoginCountor[] countors = map.values().toArray(new UserLoginCountor[0]);
		int scope = Math.min(10, countors.length);
		for (int i = 0; i < scope; i++) {
			for (int j = i + 1; j < countors.length; j++) {
				if (countors[j].getCount() > countors[i].getCount()) {
					UserLoginCountor temp = countors[j];
					countors[j] = countors[i];
					countors[i] = temp;
				}
			}
			System.out.println(countors[i]);
		}
	}

	/**
	 * 最普通的阻塞计数,最大计数Long.MAX_VALUE
	 */
	private static void userLoginCountSortUseTwoMap() {
		List<User> users = UserLoginData.getUsers();
		//filter
		//count
		long loginTimeBorder = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10);
		HashMap<Long, Long> id2Counts = new HashMap<Long, Long>();
		HashMap<Long, User> id2Users = new HashMap<Long, User>();
		for (User user : users) {
			if (user.getLoginTime() < loginTimeBorder)
				continue;
			long userId = user.getUserId();
			if (!id2Users.containsKey(userId))
				id2Users.put(userId, user);
			Long count = id2Counts.get(userId);
			if (count == null)
				count = 0L;
			id2Counts.put(userId, ++count);
		}
		//sort
		//print
		@SuppressWarnings("unchecked")
		Entry<Long, Long>[] id2CountEntries = id2Counts.entrySet().toArray(new Map.Entry[0]);

		int scope = Math.min(10, id2CountEntries.length);
		for (int i = 0; i < scope; i++) {
			for (int j = i + 1; j < id2CountEntries.length; j++) {
				if (id2CountEntries[j].getValue() > id2CountEntries[i].getValue()) {
					Entry<Long, Long> temp = id2CountEntries[j];
					id2CountEntries[j] = id2CountEntries[i];
					id2CountEntries[i] = temp;
				}
			}
			System.out.println("loginCount = " + id2CountEntries[i].getValue() + ", "
					+ id2Users.get(id2CountEntries[i].getKey()));
		}
	}
}